import java.awt.Point;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Random;

public class Game {
	
	private String info;
	/*
	 * 0 - me
	 * 1 - enemy
	 * 2 - random
	 */
	private int start;
	
	private User owner;
	private User opponent;
	private int y;
	private int x;
	private int k;
	
	private int counter;
	
	private User nextMove;
	private char mark;
	
	private char field[][];
	
	private GameViewDialog dlg;

	public Game(User owner, String info, int x, int y, int k, int start) {
		this.info = info;
		this.owner = owner;
		this.x = x;
		this.y = y;
		this.k = k;
		
		this.start = start;
		this.mark = 'x';
		
		this.counter = 0;
	}
	
	public void start(User _opponent) {
		opponent = _opponent;
		Random rand = new Random(System.currentTimeMillis());
		
		if (start == 0)
			nextMove = owner;
		else if (start == 1)
			nextMove = opponent;
		else
			nextMove = rand.nextDouble() < 0.5 ? owner : opponent;
		
		field = new char[x][y];
		for (int i = 0; i < x; ++i) {
			for (int j = 0; j < y; ++j) {
				field[i][j] = 0;
			}
		}
	}
	
	public void move(User u, int _x, int _y) throws IOException {
		if (!u.equals(nextMove)) {
			u.send("error Game#" + this.hashCode() + ": your opponent's move");
			return;
		}
		User en = owner.equals(u) ? opponent : owner;
		
		if (_x >= x || _y >= y) {
			u.send("error Game#" + this.hashCode() + ": move coords error");
			return;
		}
		if (field[_x][_y] != 0) {
			u.send("error Game#" + this.hashCode() + ": move coords error");
			return;
		}
		
		nextMove = en;
		
		field[_x][_y] = mark;
		counter++;
		
		int count = 0;
		int i = _x;
		Deque<Point> vc = new ArrayDeque<Point>();
		Point a = null, b = null;
		
		while (field[i++][_y] == mark) {
			vc.addLast(new Point(i-1, _y));
			++count;
			if (i == x)
				break;
		}
		i = _x;
		while (field[i--][_y] == mark) {
			vc.addFirst(new Point(i+1, _y));
			++count;
			if (i == -1)
				break;
		}
		
		if ((count - 1) == k) {
			a = vc.getFirst();
			b = vc.getLast();
		}
		
		///
		
		i = _y;
		count = 0;
		vc.clear();
		
		while (field[_x][i++] == mark) {
			vc.addLast(new Point(_x, i-1));
			++count;
			if (i == y)
				break;
		}
		i = _y;
		while (field[_x][i--] == mark) {
			vc.addFirst(new Point(_x, i+1));
			++count;
			if (i == -1)
				break;
		}
		
		if (count-1 == k) {
			a = vc.getFirst();
			b = vc.getLast();
		}
		
		///
		
		i = _x;
		int j = _y;
		count = 0;
		vc.clear();
		
		while (field[i++][j++] == mark) {
			vc.addLast(new Point(i-1, j-1));
			++count;
			if (i == x || j == y)
				break;
		}
		
		i = _x;
		j = _y;
		
		while (field[i--][j--] == mark) {
			vc.addFirst(new Point(i+1, j+1));
			++count;
			if (i == -1 || j == -1)
				break;
		}
		
		if (count-1 == k) {
			a = vc.getFirst();
			b = vc.getLast();
		}
		
		///
		
		i = _x;
		j = _y;
		count = 0;
		vc.clear();
		
		while (field[i++][j--] == mark) {
			vc.addLast(new Point(i-1, j+1));
			++count;
			if (i == x || j == -1)
				break;
		}
		
		i = _x;
		j = _y;
		
		while (field[i--][j++] == mark) {
			vc.addFirst(new Point(i+1, j-1));
			if (i == -1 || j == y)
				break;
		}
		
		if (count-1 == k) {
			a = vc.getFirst();
			b = vc.getLast();
		}
		
		///
		if (dlg != null)
			dlg.showMove(_x, _y);
		
		changeMark();

		en.send("gi " + this.hashCode() + " mv " + _x + " " + _y);
		if (a != null && b != null) {
			u.send("gi " + this.hashCode() + " win " + a.x + " " + a.y + " " + b.x + " " + b.y);
			en.send("gi " + this.hashCode() + " lose " + a.x + " " + a.y + " " + b.x + " " + b.y);
			remove();
			return;
		}
		
		if (counter == x*y) {
			u.send("gi " + this.hashCode() + " tie");
			en.send("gi " + this.hashCode() + " tie");
			remove();
			return;
		}
	}
	
	private void changeMark() {
		//mark = (char) ('x' + 'o' - mark);
		mark = (mark == 'x' ? 'o' : 'x');
	}
	
	public void remove() {
		owner.setGameCreated(false);
		ServerEngine.getInstance().removeGame(this);
		ServerFrame.getInstance().removeGame(this);
	}
	
	public void createDlg() {
		if (dlg == null)
			dlg = new GameViewDialog(this);
	}
	
	public void removeDlg() {
		dlg = null;
	}

	public char[][] getField() {
		return field;
	}

	@Override
	public String toString() {
		return "<html>Game#" + hashCode() + ": " + info + " - <img src='file:x.png' alt='X: '></img> " + y +
				" - <img src='file:y.png' alt='Y: '></img> " + x + " - <img src='file:k.png' alt='K: '></img> " + k +
				(start == 0 ? " - <img src='file:owner.png' alt='Game owner'></img> " : (start == 1 ? 
				" - <img src='file:opponent.png' alt='Opponent'></img> " : " - <img src='file:random.png' alt='Random'></img> ")) + "</html>";
	}

	public String getInfo() {
		return info;
	}
	
	public int getStart() {
		return start;
	}

	public User getOpponent() {
		return opponent;
	}

	public int getY() {
		return y;
	}

	public int getX() {
		return x;
	}

	public int getK() {
		return k;
	}

	public User getNextMove() {
		return nextMove;
	}

	public User getOwner() {
		return owner;
	}
}
